﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Reflection;
using System.Text;

namespace Mozlite
{
    /// <summary>
    /// 数据库读取器扩展方法类。
    /// </summary>
    public static class IDataReaderExtensions
    {
        #region size
        /// <summary>
        /// 获取数据库返回的总记录数，一般在查询字符串后面加一句“SELECT COUNT(*) FROM ...”。
        /// </summary>
        /// <param name="reader"><see cref="T:System.Data.IDataReader"/>对象。</param>
        /// <param name="sizeName">总数量的列名。</param>
        /// <returns>返回数据库返回的总记录数。</returns>
        public static int GetSize(this IDataReader reader, string sizeName = null)
        {
            if (reader.NextResult() && reader.Read())
                return sizeName == null ? reader.GetInt32(0) : reader.GetInt32(sizeName);
            return 0;
        }
        #endregion

        #region boolean
        /// <summary>
        /// 获取数据库中列值。
        /// </summary>
        /// <param name="dr"><see cref="T:System.Data.IDataRecord"/>实例对象。</param>
        /// <param name="name">列名称。</param>
        /// <param name="defaultValue">默认值。</param>
        /// <returns>返回该类的值。</returns>
        public static bool GetBoolean(this IDataRecord dr, string name, bool defaultValue = false)
        {
            return dr.TConvert<bool>(name, defaultValue, o => { return Convert.ToBoolean(o); });
        }
        #endregion

        #region byte
        /// <summary>
        /// 获取数据库中列值。
        /// </summary>
        /// <param name="dr"><see cref="T:System.Data.IDataRecord"/>实例对象。</param>
        /// <param name="name">列名称。</param>
        /// <param name="defaultValue">默认值。</param>
        /// <returns>返回该类的值。</returns>
        public static byte GetByte(this IDataRecord dr, string name, byte defaultValue = default(byte))
        {
            return dr.TConvert<byte>(name, defaultValue, o => { return Convert.ToByte(o); });
        }
        #endregion

        #region sbyte
        /// <summary>
        /// 获取数据库中列值。
        /// </summary>
        /// <param name="dr"><see cref="T:System.Data.IDataRecord"/>实例对象。</param>
        /// <param name="name">列名称。</param>
        /// <param name="defaultValue">默认值。</param>
        /// <returns>返回该类的值。</returns>
        public static sbyte GetBytes(this IDataRecord dr, string name, sbyte defaultValue = default(sbyte))
        {
            return dr.TConvert<sbyte>(name, defaultValue, o => { return Convert.ToSByte(o); });
        }
        #endregion

        #region char
        /// <summary>
        /// 获取数据库中列值。
        /// </summary>
        /// <param name="dr"><see cref="T:System.Data.IDataRecord"/>实例对象。</param>
        /// <param name="name">列名称。</param>
        /// <param name="defaultValue">默认值。</param>
        /// <returns>返回该类的值。</returns>
        public static char GetChar(this IDataRecord dr, string name, char defaultValue = default(char))
        {
            return dr.TConvert<char>(name, defaultValue, o => { return Convert.ToChar(o); });
        }
        #endregion

        #region datetime
        /// <summary>
        /// 获取数据库中列值。
        /// </summary>
        /// <param name="dr"><see cref="T:System.Data.IDataRecord"/>实例对象。</param>
        /// <param name="name">列名称。</param>
        /// <param name="defaultValue">默认值。</param>
        /// <returns>返回该类的值。</returns>
        public static DateTime GetDateTime(this IDataRecord dr, string name, DateTime defaultValue = default(DateTime))
        {
            return dr.TConvert<DateTime>(name, defaultValue, o => { return Convert.ToDateTime(o); });
        }
        #endregion

        #region decimal
        /// <summary>
        /// 获取数据库中列值。
        /// </summary>
        /// <param name="dr"><see cref="T:System.Data.IDataRecord"/>实例对象。</param>
        /// <param name="name">列名称。</param>
        /// <param name="defaultValue">默认值。</param>
        /// <returns>返回该类的值。</returns>
        public static decimal GetDecimal(this IDataRecord dr, string name, decimal defaultValue = default(decimal))
        {
            return dr.TConvert<decimal>(name, defaultValue, o => { return Convert.ToDecimal(o); });
        }
        #endregion

        #region double
        /// <summary>
        /// 获取数据库中列值。
        /// </summary>
        /// <param name="dr"><see cref="T:System.Data.IDataRecord"/>实例对象。</param>
        /// <param name="name">列名称。</param>
        /// <param name="defaultValue">默认值。</param>
        /// <returns>返回该类的值。</returns>
        public static double GetDouble(this IDataRecord dr, string name, double defaultValue = default(double))
        {
            return dr.TConvert<double>(name, defaultValue, o => { return Convert.ToDouble(o); });
        }
        #endregion

        #region float
        /// <summary>
        /// 获取数据库中列值。
        /// </summary>
        /// <param name="dr"><see cref="T:System.Data.IDataRecord"/>实例对象。</param>
        /// <param name="name">列名称。</param>
        /// <param name="defaultValue">默认值。</param>
        /// <returns>返回该类的值。</returns>
        public static float GetFloat(this IDataRecord dr, string name, float defaultValue = default(float))
        {
            return dr.TConvert<float>(name, defaultValue, o => { return Convert.ToSingle(o); });
        }
        #endregion

        #region guid
        /// <summary>
        /// 获取数据库中列值。
        /// </summary>
        /// <param name="dr"><see cref="T:System.Data.IDataRecord"/>实例对象。</param>
        /// <param name="name">列名称。</param>
        /// <param name="defaultValue">默认值。</param>
        /// <returns>返回该类的值。</returns>
        public static Guid GetGuid(this IDataRecord dr, string name, Guid defaultValue = default(Guid))
        {
            return dr.TConvert<Guid>(name, defaultValue, o =>
            {
                try
                {
                    return (Guid)o;
                }
                catch { return new Guid(o.ToString()); }
            });
        }
        #endregion

        #region int16
        /// <summary>
        /// 获取数据库中列值。
        /// </summary>
        /// <param name="dr"><see cref="T:System.Data.IDataRecord"/>实例对象。</param>
        /// <param name="name">列名称。</param>
        /// <param name="defaultValue">默认值。</param>
        /// <returns>返回该类的值。</returns>
        public static short GetInt16(this IDataRecord dr, string name, short defaultValue = 0)
        {
            return dr.TConvert<short>(name, defaultValue, o => { return Convert.ToInt16(o); });
        }
        #endregion

        #region int32
        /// <summary>
        /// 获取数据库中列值。
        /// </summary>
        /// <param name="dr"><see cref="T:System.Data.IDataRecord"/>实例对象。</param>
        /// <param name="name">列名称。</param>
        /// <param name="defaultValue">默认值。</param>
        /// <returns>返回该类的值。</returns>
        public static int GetInt32(this IDataRecord dr, string name, int defaultValue = 0)
        {
            return dr.TConvert<int>(name, defaultValue, o => { return Convert.ToInt32(o); });
        }
        #endregion

        #region int64
        /// <summary>
        /// 获取数据库中列值。
        /// </summary>
        /// <param name="dr"><see cref="T:System.Data.IDataRecord"/>实例对象。</param>
        /// <param name="name">列名称。</param>
        /// <param name="defaultValue">默认值。</param>
        /// <returns>返回该类的值。</returns>
        public static long GetInt64(this IDataRecord dr, string name, long defaultValue = default(long))
        {
            return dr.TConvert<long>(name, defaultValue, o => { return Convert.ToInt64(o); });
        }
        #endregion

        #region uint16
        /// <summary>
        /// 获取数据库中列值。
        /// </summary>
        /// <param name="dr"><see cref="T:System.Data.IDataRecord"/>实例对象。</param>
        /// <param name="name">列名称。</param>
        /// <param name="defaultValue">默认值。</param>
        /// <returns>返回该类的值。</returns>
        public static ushort GetUInt16(this IDataRecord dr, string name, ushort defaultValue = 0)
        {
            return dr.TConvert<ushort>(name, defaultValue, o => { return Convert.ToUInt16(o); });
        }
        #endregion

        #region uint32
        /// <summary>
        /// 获取数据库中列值。
        /// </summary>
        /// <param name="dr"><see cref="T:System.Data.IDataRecord"/>实例对象。</param>
        /// <param name="name">列名称。</param>
        /// <param name="defaultValue">默认值。</param>
        /// <returns>返回该类的值。</returns>
        public static uint GetUInt32(this IDataRecord dr, string name, uint defaultValue = 0)
        {
            return dr.TConvert<uint>(name, defaultValue, o => { return Convert.ToUInt32(o); });
        }
        #endregion

        #region uint64
        /// <summary>
        /// 获取数据库中列值。
        /// </summary>
        /// <param name="dr"><see cref="T:System.Data.IDataRecord"/>实例对象。</param>
        /// <param name="name">列名称。</param>
        /// <param name="defaultValue">默认值。</param>
        /// <returns>返回该类的值。</returns>
        public static ulong GetUInt64(this IDataRecord dr, string name, ulong defaultValue = default(ulong))
        {
            return dr.TConvert<ulong>(name, defaultValue, o => { return Convert.ToUInt64(o); });
        }
        #endregion

        #region string
        /// <summary>
        /// 获取数据库中列值。
        /// </summary>
        /// <param name="dr"><see cref="T:System.Data.IDataRecord"/>实例对象。</param>
        /// <param name="name">列名称。</param>
        /// <param name="defaultValue">默认值。</param>
        /// <returns>返回该类的值。</returns>
        public static string GetString(this IDataRecord dr, string name, string defaultValue = null)
        {
            return dr.TConvert<string>(name, defaultValue, o => { return Convert.ToString(o); });
        }
        #endregion

        #region helper
        private static T TConvert<T>(this IDataRecord dr, string name, T defaultValue, Func<object, T> converter)
        {
            try
            {
                object value = dr[name];
                if (value == DBNull.Value)
                    return defaultValue;
                return converter(value);
            }
            catch { }
            return defaultValue;
        }
        #endregion

        #region encoding
        /// <summary>
        /// 获取数据库中列值。
        /// </summary>
        /// <param name="dr"><see cref="T:System.Data.IDataRecord"/>实例对象。</param>
        /// <param name="name">列名称。</param>
        /// <param name="defaultValue">默认值，如果为空默认为UTF-8。</param>
        /// <returns>返回该类的值。</returns>
        public static Encoding GetEncoding(this IDataRecord dr, string name, Encoding defaultValue = null)
        {
            if (defaultValue == null)
                defaultValue = Encoding.UTF8;
            return dr.TConvert<Encoding>(name, defaultValue, o => { return Encoding.GetEncoding(o as string); });
        }
        #endregion

        #region version
        /// <summary>
        /// 获取数据库中列值。
        /// </summary>
        /// <param name="dr"><see cref="T:System.Data.IDataRecord"/>实例对象。</param>
        /// <param name="name">列名称。</param>
        /// <param name="defaultValue">默认值。</param>
        /// <returns>返回该类的值。</returns>
        public static Version GetVersion(this IDataRecord dr, string name, Version defaultValue = null)
        {
            return dr.TConvert<Version>(name, defaultValue, o => { return new Version(o as string); });
        }
        #endregion

        #region reflector
        /// <summary>
        /// 实体类型赋值。
        /// </summary>
        /// <typeparam name="T">实体类型。</typeparam>
        /// <param name="reader">数据库读取器。</param>
        /// <param name="serializableFieldName">序列化列名称。</param>
        /// <returns>返回实例对象。</returns>
        public static T As<T>(this IDataReader reader, string serializableFieldName = null) where T : class, new()
        {
            //添加序列化读取
            T retValue = null;
            if(serializableFieldName.HasValue()) {
                var xml = reader.GetString(serializableFieldName);
                retValue = Cores.Deserialize<T>(xml);
                if(retValue == null)
                    retValue = new T();
            }
            else
                retValue = new T();
            object value;
            foreach (PropertyInfo p in typeof(T).GetProperties(BindingFlags.Instance | BindingFlags.GetProperty | BindingFlags.Public | BindingFlags.SetProperty))
            {
                try
                {
                    value = reader[p.Name];
                    if (value != null)
                    {
                        p.SetValue(retValue, value.ChangeType(p.PropertyType), null);
                    }
                }
                catch
                {
                }
            }
            return retValue;
        }

        /// <summary>
        /// 实体类型赋值。
        /// </summary>
        /// <typeparam name="T">实体类型。</typeparam>
        /// <param name="reader">数据库读取器。</param>
        /// <param name="fieldName">列名称。</param>
        /// <param name="defaultValue">默认值，即转换失败后返回的值。</param>
        /// <returns>返回实例对象。</returns>
        public static T Get<T>(this IDataReader reader, string fieldName, T defaultValue = default(T))
        {
            object value = defaultValue;
            try
            {
                value = reader[fieldName];
                return value.To<T>(defaultValue);
            }
            catch { }
            return defaultValue;
        }
        #endregion
    }
}
